

package yf.mall.service.impl.app;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.Transactional;
import yf.mall.common.Const;
import yf.mall.component.app.AppDyAuthCompoent;
import yf.mall.component.helper.OrderHelper;
import yf.mall.dao.DyAccountAuthDao;
import yf.mall.dysdk.model.DyKolOrder;
import yf.mall.dysdk.model.DyKolOrderList;
import yf.mall.dysdk.model.DyToken;
import yf.mall.dysdk.model.request.DyKolOrderRequest;
import yf.mall.dysdk.service.DyAllianceApiService;
import yf.mall.entity.DyAccountAuthEntity;
import yf.mall.entity.KolOrderEntityExample;
import yf.mall.entity.custom.PageQuery;
import yf.mall.mapper.KolOrderExtMapper;
import yf.mall.service.NoticeService;
import yf.mall.utils.RecursionPageQuerier;
import yf.mall.utils.StringUtil;
import yf.mall.vo.up.KolOrderUp;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.excel.context.AnalysisContext;

import java.io.InputStream;

import com.alibaba.excel.event.AnalysisEventListener;
import org.springframework.stereotype.Service;
import com.alibaba.excel.EasyExcel;
import yf.mall.vo.down.KolOrderDown;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.net.URLEncoder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.stream.Collectors;

import yf.mall.dao.KolOrderDao;
import yf.mall.entity.KolOrderEntity;
import yf.mall.vo.KolOrderVo;
import yf.mall.service.app.KolOrderService;
import com.yf.service.impl.BaseServiceImpl;

/**
 * 账户记录Service实现类
 *
 *
 *
 * @date Tue Jul 18 14:30:26 CST 2023
 */
@Slf4j
@Service
@EnableAsync
public class KolOrderServiceImpl extends BaseServiceImpl<KolOrderEntity> implements KolOrderService {
    @Resource
    private KolOrderDao dao;

    @Resource
    private KolOrderExtMapper kolOrderExtMapper;

    @Resource
    @Lazy
    private AppDyAuthCompoent appDyAuthCompoent;

    @Resource
    private DyAllianceApiService dyAllianceApiService;


    @Autowired
    public void setDao(KolOrderDao dao) {
        this.dao = dao;
        super.setBaseDao(dao);
    }


    @Override
    public List<KolOrderVo> findVo(KolOrderVo vo) {
        return dao.findVo(vo);
    }

    @Override
    public KolOrderVo getVo(Long id) {
        return dao.getVo(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveVo(KolOrderVo vo) {
        return dao.save(vo.getEntity());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateVo(KolOrderVo vo) {
        return dao.update(vo.getEntity());
    }


    @Override
    public void downLoad(HttpServletResponse response, List<KolOrderVo> list) {
        try {
            List<KolOrderDown> datas = list.stream().map(item -> new KolOrderDown(item)).collect(Collectors.toList());
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("测试", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), KolOrderDown.class).sheet("模板").doWrite(datas);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    @Override
    public void upload(InputStream file) {
        EasyExcel.read(file, KolOrderUp.class, new UploadDataListener()).sheet().doRead();
    }


    class UploadDataListener extends AnalysisEventListener<KolOrderUp> {


        @Override
        @Transactional(rollbackFor = Exception.class)
        public void invoke(KolOrderUp upVo, AnalysisContext analysisContext) {
            saveVo(upVo.toVo());
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }

    }


    /**内部方法**/


    /**
     * 外部方法实现
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int save(KolOrderEntity entity) {
        return kolOrderExtMapper.insertSelective(entity);
    }

    @Override
    public PageInfo<KolOrderEntity> page(KolOrderEntityExample example, PageQuery page) {
        PageHelper.startPage(page.getPageNumber(), page.getPageSize());
        List<KolOrderEntity> entityList = kolOrderExtMapper.selectByExample(example);
        return new PageInfo(entityList);
    }

    @Override
    public Integer notifyOrder(Long userId, Date beginDate, Date endDate, Integer maxLimit) {
        log.info("同步用户{}的订单数据，开始时间={}，结束时间={}", userId, beginDate, endDate);
        List<DyToken> allTokens = appDyAuthCompoent.getAllTokenByUser(userId);
        List<DyKolOrder> orders = new ArrayList<>();
        Long time = System.currentTimeMillis();
        for (DyToken dyToken : allTokens) {
            DyKolOrderRequest request = new DyKolOrderRequest();
            request.setStartTime(beginDate);
            request.setEndTime(endDate);
            request.setTimeType("pay");
            request.setSize(Const.DY_ORDER_MAX_QUERY_SIZE);
            String cursor = "1";
            // 为了防止死循环，增加最大循环次数条件
            if (maxLimit == null) {
                maxLimit = Const.DY_ORDER_MAX_QUERY_SIZE * Const.DY_ORDER_MAX_QUERY_TIMES;
            }
            int maxCount = 0;
            while (StringUtils.isNotBlank(cursor) && maxCount <= maxLimit / Const.DY_ORDER_MAX_QUERY_SIZE) {
                maxCount++;
                DyKolOrderList kolOrders = dyAllianceApiService.getKolOrders(dyToken, request);
                cursor = kolOrders.getCursor();
                request.setCursor(kolOrders.getCursor());
                if (CollectionUtils.isEmpty(kolOrders.getOrders())) {
                    continue;
                }
                orders.addAll(kolOrders.getOrders());
            }
        }
        log.info("从抖音获取用户{}从{}到{}的订单,共{}条,耗时:{}毫秒", userId, beginDate, endDate, orders.size(), System.currentTimeMillis() - time);
//        log.info("查询用户{}抖音数据成功，时间{}范围内的抖音订单一共{}条", userId, beginDate, orders.size());
        // 保存订单记录
        int successCount = 0;
        time = System.currentTimeMillis();
        for (DyKolOrder dyKolOrder : orders) {
            KolOrderEntity kolOrderEntity = OrderHelper.convertDyToDb(dyKolOrder);
            int result = saveOrUpdateOrder(kolOrderEntity);
            successCount += result;
        }
        log.info("数据库写入用户{},{}数据耗时:{}", userId, orders.size(), System.currentTimeMillis() - time);
        return successCount;
    }

    private int saveOrUpdateOrder(KolOrderEntity kolOrderEntity) {
        try {
            KolOrderEntity dbOrder = get(kolOrderEntity.getId());
            if (dbOrder == null) {
                return save(kolOrderEntity);
            } else {
                return update(kolOrderEntity);
            }
        } catch (Exception e) {
            return 0;
        }
    }


    @Override
    @Async
    public Integer notifyOrderAsync(Long userId, Date beginDate, Date endDate, Integer maxLimit) {
        log.info("开始异步支持，同步订单数据");
        Integer successCount = notifyOrder(userId, beginDate, endDate, maxLimit);
        log.info("异步支持同步订单数据，userId={}，begin={}，end={}，result={}", userId, beginDate, endDate, successCount);
        return successCount;
    }

    @Resource
    private DyAccountAuthDao dyAccountAuthDao;

    @Override
    @Async
    public Integer notifyOrderAsync(Date beginDate, Date endDate, Integer maxLimit) {
        //找到所有的授权的用户
        List<DyAccountAuthEntity> auths = dyAccountAuthDao.findAll();
        Integer sum = 0;
        for (DyAccountAuthEntity auth :
                auths) {
            sum += notifyOrderAsync(auth.getUserId(), beginDate, endDate, maxLimit);
        }
        return sum;
    }

    @Override
    public List<KolOrderEntity> getKolOrderByPayTime(List<DyToken> tokens, Long pid, Date begin, Date end) {
        List<String> openIds = tokens.stream().map(DyToken::getOpenId).collect(Collectors.toList());
        RecursionPageQuerier<KolOrderEntity> recursionPageQuerier = new RecursionPageQuerier<>(
                Const.INTEGER_MAX_QUERY_SIZE, Const.INTEGER_MAX_QUERY_TIMES);
        KolOrderEntityExample example = new KolOrderEntityExample();
        KolOrderEntityExample.Criteria criteria = example.createCriteria();
        criteria.andPaySuccessTimeBetween(begin, end).andAuthorOpenidIn(openIds);
        if (pid != null) {
            criteria.andProductIdEqualTo(pid);
        }
        return recursionPageQuerier.query(pageQuery -> {
            PageInfo<KolOrderEntity> page = page(example, pageQuery);
            return page.getList();
        });
    }

    @Override
    public List<KolOrderEntity> getKolOrderBySettleTime(List<DyToken> tokens, Long pid, Date begin, Date end) {
        List<String> openIds = tokens.stream().map(DyToken::getOpenId).collect(Collectors.toList());
        RecursionPageQuerier<KolOrderEntity> recursionPageQuerier = new RecursionPageQuerier<>(
                Const.INTEGER_MAX_QUERY_SIZE, Const.INTEGER_MAX_QUERY_TIMES);
        KolOrderEntityExample example = new KolOrderEntityExample();
        KolOrderEntityExample.Criteria criteria = example.createCriteria();
        criteria.andSettleTimeBetween(begin, end).andAuthorOpenidIn(openIds);
        if (pid != null) {
            criteria.andProductIdEqualTo(pid);
        }
        return recursionPageQuerier.query(pageQuery -> {
            PageInfo<KolOrderEntity> page = page(example, pageQuery);
            return page.getList();
        });
    }

    @Override
    public BigDecimal countOrderTotalPayAmount(List<String> openIds, Long productId) {
        return kolOrderExtMapper.countOrderTotalPayAmount(openIds, productId);
    }

    @Override
    public BigDecimal countOrderEstimatedTotalCommission(List<String> openIds, Long productId) {
        return kolOrderExtMapper.countOrderEstimatedTotalCommission(openIds, productId);
    }

    @Override
    public Long countOrders(List<String> openIds, Long productId) {
        return kolOrderExtMapper.countOrders(openIds, productId);
    }

    @Resource
    private NoticeService noticeService;

    @Override
    @Async
    public void sendExpOrder(String openId,DyKolOrder dyKolOrder) {
        if(StringUtil.isBlank(openId)){
            return;
        }
        //支付时间一分钟前
        Date startDate = DateUtils.addMinutes(dyKolOrder.getPaySuccessTime(),-1);
        List<KolOrderEntity> list = dao.findByAuthIdAndTimeAndProduct(dyKolOrder.getAuthorOpenid(),startDate,dyKolOrder.getPaySuccessTime(), dyKolOrder.getProductId());
        if(list.size()>=3){ //一分钟超过三单 通知爆单
            noticeService.sendDyExpOrder(openId,dyKolOrder.getAuthorAccount(),dyKolOrder.getProductName(),list.size(),dyKolOrder.getPaySuccessTime());
        }
    }

    @Override
    public KolOrderEntity findByOpenIdDesc(String openId) {
        return dao.findByOpenIdDesc(openId);
    }
}
